namespace ScrumSprintMonitor.ConfigEditor
{
    #region #using Directives

    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Security.Permissions;
    using System.Windows;
    using System.Windows.Controls;

    using Implementation;

    using Infrastructure;
    using Infrastructure.IoC;

    using Microsoft.Practices.ServiceLocation;
    using Microsoft.Practices.Unity;

    using UI.Wpf;

    using Views.ConfigurationView;

    #endregion

    public class Bootstrapper
    {
        private readonly IList<IModule> additionalContainerModulesList = new List<IModule>();
        private readonly Assembly assembly = Assembly.GetExecutingAssembly();
        private CompositionContainer compositionContainer;
        private UnityContainerAbstraction unityContainerAbstraction;

        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
        public Bootstrapper()
        {
            DesignerProperties.GetIsInDesignMode = (object x) => StubDesignerProperties.GetIsInDesignMode(null);

            Application.Current.Exit += OnApplicationExit;
        }

        [ImportMany(typeof(IModule))]
        public IList<IModule> AdditionalContainerModules
        {
            [DebuggerStepThrough]
            get { return this.additionalContainerModulesList; }
        }

        public void Run()
        {
            DesignerProperties.GetIsInDesignMode = (object x) => StubDesignerProperties.GetIsInDesignMode(null);

            EventManager.RegisterClassHandler(typeof(TextBox), UIElement.GotFocusEvent,
                                              new RoutedEventHandler((sender, e) => ((TextBox) sender).SelectAll()));

            this.unityContainerAbstraction = UnityContainerAbstraction.EnsureContainerIsSetUp();
            UnityContainerAbstraction.RegisterModule<UnityAppRuntimeModule>();
            this.unityContainerAbstraction.LoadRegisteredModules(false);

            if (Compose())
            {
                this.unityContainerAbstraction.Instance.Load(AdditionalContainerModules);

                var container = ServiceLocator.Current.GetInstance<IUnityContainer>();

                var model = container.Resolve<IConfigurationViewModel>();
                var optionsDialog = new ConfigurationWindow(model);
                if (optionsDialog.ShowDialog().GetValueOrDefault(false))
                {
                    if (!Settings.Default.IsReadOnly)
                    {
                        Settings.Default.Save();
                    }

                    Application.Current.Shutdown(1);
                    return;
                }
            }

            Application.Current.Shutdown(0);
        }

        private bool Compose()
        {
            //this.logger.Debug("Composing MEF container...");

            var aggregateCatalog = new AggregateCatalog();
            string binFolder = Path.GetDirectoryName(this.assembly.Location);
            //string addInsBinFolder = Path.Combine(binFolder, @"AddIns");
            string serverAdaptersBinFolder = Path.Combine(binFolder, @"AddIns\ServerAdapters");

            AddCatalogFromFolderPath(aggregateCatalog, serverAdaptersBinFolder);
            //AddCatalogFromFolderPath(aggregateCatalog, addInsBinFolder);

            //this.logger.Debug("Found {0} parts in {1} MEF catalogs:", aggregateCatalog.Parts.Count(), aggregateCatalog.Catalogs.Count);
            Debug.Assert(aggregateCatalog.Parts.Any());

            this.compositionContainer = new CompositionContainer(aggregateCatalog);

            var batch = new CompositionBatch();
            batch.AddPart(this);
            batch.AddPart(ServiceLocator.Current.GetInstance<IProcessTemplateAdapterProvider>());
            batch.AddExportedValue(ServiceLocator.Current.GetInstance<IServiceLocator>());

            try
            {
                this.compositionContainer.Compose(batch);
            }
            catch (CompositionException compositionException)
            {
                //this.logger.Fatal(compositionException, "Found exception while composing MEF container.");

                MessageBox.Show(compositionException.ToString());
                return false;
            }

            return true;
        }

        private static void AddCatalogFromFolderPath(AggregateCatalog aggregateCatalog, string binFolder)
        {
            if (Directory.Exists(binFolder))
            {
                //this.logger.Debug("Creating MEF DirectoryCatalog from {0}...", binFolder);

                var addinsDirectoryCatalog = new DirectoryCatalog(binFolder);
                aggregateCatalog.Catalogs.Add(addinsDirectoryCatalog);

                //foreach (var part in addinsDirectoryCatalog.Parts)
                //{
                //this.logger.Debug("{0}", part.ToString());
                //}
            }
            else
            {
                //this.logger.Debug("{0} addin folder not found.", binFolder);
            }
        }

        private void OnApplicationExit(object sender, ExitEventArgs e)
        {
            if (this.compositionContainer != null)
            {
                this.compositionContainer.Dispose();
            }

            //this.unityContainerAbstraction.Dispose();
        }
    }
}
